package com.xs.tool.common.excel;


import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;

import com.xs.tool.common.excel.model.ExcelImportResultDto;
import com.xs.tool.common.excel.model.ImportExcelValidHelper;
import com.xs.tool.common.excel.model.ImportFailDto;
import com.xs.tool.common.excel.model.ImportSuccessDto;
import com.xs.tool.common.excel.service.HandleImportExcelService;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 使用
 *public void importExcel(HttpServletResponse response,HttpServletRequest request)throws Exception{
    *ExcelImportListener excelImportListener=new ExcelImportListener(handleImportExcelService,ExcelImportTemplateDto.class);
    *         // 读取数据
    *ExcelUtil.readExcel(request,"file",0,1,excelImportListener,ExcelImportTemplateDto.class);
    *         // 错误集
    *List<ImportFailDto> importFailDtoList=excelImportListener.getImportFailDtoList();
    *if(!importFailDtoList.isEmpty()){
    *List<ExcelTemplateCompleteDto> excelTemplateCompleteDtoList=importFailDtoList.stream().map(current->{
    *ExcelTemplateCompleteDto excelTemplateCompleteDto=new ExcelTemplateCompleteDto();
    *BeanUtils.copyProperties(current.getObject(),excelTemplateCompleteDto);
    *                 // 设置错误信息
    *excelTemplateCompleteDto.setErrMsg(current.getErrMsg());
    *return excelTemplateCompleteDto;
    *}).collect(Collectors.toList());
    *             //导出excel(PS:主要用于将错误的数据导出)
    *String fileName=URLEncoder.encode("导入结果","UTF-8");
    *ExcelUtil.writeExcel(response,excelTemplateCompleteDtoList,fileName,ExcelTemplateCompleteDto.class);
    *}
    *}
 * @ Author     ：scw
 * @ Date       ：Created in 下午 8:54 2020/3/31 0031
 * @ Description：导入excel的监听处理类
 * @ Modified By：
 * @Version: $version$
 */
public class ExcelImportListener<T>  extends AnalysisEventListener<T>{
    // 导入成功的数据
    private List<ImportSuccessDto> importSuccessDtoList = new ArrayList<>();
    // 导入失败的数据
    private List<ImportFailDto> importFailDtoList = new ArrayList<>();

    private List<T> list = new ArrayList<>();
    // 处理导入数据的逻辑
    private HandleImportExcelService handleImportExcelService;

    private Class<T> tClass;

    public List<ImportSuccessDto> getImportSuccessDtoList() {
        return importSuccessDtoList;
    }

    public void setImportSuccessDtoList(List<ImportSuccessDto> importSuccessDtoList) {
        this.importSuccessDtoList = importSuccessDtoList;
    }

    public List<ImportFailDto> getImportFailDtoList() {
        return importFailDtoList;
    }

    public void setImportFailDtoList(List<ImportFailDto> importFailDtoList) {
        this.importFailDtoList = importFailDtoList;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public HandleImportExcelService getHandleImportExcelService() {
        return handleImportExcelService;
    }

    public void setHandleImportExcelService(HandleImportExcelService handleImportExcelService) {
        this.handleImportExcelService = handleImportExcelService;
    }

    public Class<T> gettClass() {
        return tClass;
    }

    public void settClass(Class<T> tClass) {
        this.tClass = tClass;
    }

    public ExcelImportListener(HandleImportExcelService handleImportExcelService) {
        this.handleImportExcelService = handleImportExcelService;
    }

    public ExcelImportListener(HandleImportExcelService handleImportExcelService, Class<T> tClass) {
        this.handleImportExcelService = handleImportExcelService;
        this.tClass = tClass;
    }

    /**
     * 导入数据的处理逻辑
     * @param t
     * @param analysisContext
     */
    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        //错误提示
        String msg = "";
        try {
            msg = ImportExcelValidHelper.checkDataValid(t);
        }catch (Exception e){
            msg = "解析处理校验异常";
        }
        // 如果校验失败
        if(msg.length() != 0){
            ImportFailDto importFailDto = new ImportFailDto(t, msg);
            importFailDtoList.add(importFailDto);
        }else{
            list.add(t);
        }
        // 每1000条处理一次(PS:根据需求来即可)
        if(list.size() > 1000){
            ExcelImportResultDto excelImportResultDto = handleImportExcelService.checkImportData(list);
            if(excelImportResultDto.getSuccessDtoList().size() >= 0){
                importSuccessDtoList.addAll(excelImportResultDto.getSuccessDtoList());
            }
            if(excelImportResultDto.getFailDtoList().size() >= 0){
                importFailDtoList.addAll(excelImportResultDto.getFailDtoList());
            }
            list.clear();
        }
    }

    /**
     * 所有数据处理完之后的处理方法
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // PS:之所以最后这里还进行处理是防止最后一次的数据量没有达到批量值
        ExcelImportResultDto excelImportResultDto = handleImportExcelService.checkImportData(list);
        if(excelImportResultDto.getSuccessDtoList().size() >= 0){
            importSuccessDtoList.addAll(excelImportResultDto.getSuccessDtoList());
        }
        if(excelImportResultDto.getFailDtoList().size() >= 0){
            importFailDtoList.addAll(excelImportResultDto.getFailDtoList());
        }
        list.clear();
    }

    /**
     * 校验导入的表格的头是否匹配
     * @param headMap
     * @param analysisContext
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext analysisContext){
        super.invokeHeadMap(headMap, analysisContext);
        if(tClass != null){
            try {
                // 获取Excel导入实体的单元格内容
                Map<Integer, String> indexNameMap = getIndexName(tClass);
                Set<Integer> keySet = indexNameMap.keySet();
                for (Integer key: keySet) {
                    // 头表是否存在空值
                    if(headMap.get(key).length() == 0){
                        throw new ExcelAnalysisException("Excel格式非法");
                    }
                    // 对比导入Excel实体模板和当前上传Excel是否匹配
                    if(!headMap.get(key).equals(indexNameMap.get(key))){
                        throw new ExcelAnalysisException("Excel格式非法");
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private Map<Integer, String> getIndexName(Class<T> tClass) throws NoSuchFieldException {
        Map<Integer, String> result = new HashMap<>();
        Field[] declaredFields = tClass.getDeclaredFields();
        for (Field currentField: declaredFields) {
            currentField.setAccessible(true);
            ExcelProperty annotation = currentField.getAnnotation(ExcelProperty.class);
            if(annotation != null){
                int index =annotation.index();
                String[] value = annotation.value();
                StringBuilder sb = new StringBuilder();
                for (String cur : value) {
                    sb.append(cur);
                }
                result.put(index, sb.toString());
            }
        }
        return result;
    }


}
